package com.filetransfer.api.upload;
import com.filetransfer.api.generated.FileControllerApi;
import com.filetransfer.api.generated.invoker.ApiClient;
import com.filetransfer.api.generated.invoker.ApiException;
import com.filetransfer.api.generated.models.FileUploadInfo;

import java.lang.reflect.Type;

import com.filetransfer.api.ApiHelper;
import com.google.gson.reflect.TypeToken;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class FileChunkUploader {
    private static final int MAX_RETRY = 5;
    private static final long FAIL_TIMEOUT = 60000;
    private final ApiClient apiClient;
    @Getter
    private final FileControllerApi fileApi;
    private final String fileName;
    private final String md5;
    private final long totalSize;
    public FileChunkUploader(String fileName, String fileMd5, long totalSize) {
        this.fileName = fileName;
        this.md5 = fileMd5;
        this.totalSize = totalSize;
        this.apiClient = ApiHelper.newApiClient();
        this.fileApi = new FileControllerApi(apiClient);
    }
    public boolean uploadFileChunk(FileChunk chunk, ProgressListener onProgress) {
        int retryCount = 0;
        long startTime = System.currentTimeMillis();
        while (retryCount < MAX_RETRY) {
            try {
                var call = fileApi.uploadChunkCall(md5, chunk.chunkMD5(), chunk.chunkIndex(), chunk.chunkOffset(), chunk.chunkData(), null);
                // 添加进度获取
                var newCall = ProgressRequestHelper.CloneCallWithProgress(apiClient, call, (bytesWritten, contentLength) -> {
                    log.info("上传进度：{} / {}", bytesWritten, contentLength);
                    onProgress.onProgress(bytesWritten, contentLength);
                });
                Type localVarReturnType = new TypeToken<String>() {}.getType();
                var result = apiClient.execute(newCall, localVarReturnType);
                long now = System.currentTimeMillis();
                log.info("分片 [{}] 上传成功，起始位置：{}，大小：{}， 分片 MD5：{}，耗时：{}ms 返回：{}", chunk.chunkIndex(), chunk.chunkOffset(), chunk.chunkData().length, chunk.chunkMD5(), now - startTime, result);
                return true;
            } catch (ApiException e) {
                retryCount++;
                log.error("上传分片失败，重试次数: " + retryCount + ", 错误信息: " + e.getMessage());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
        log.error("上传分片{}失败，超过最大重试次数", chunk.chunkIndex());
        return false;
    }
    public void start() throws ApiException {
        fileApi.newUpload(md5, new FileUploadInfo().fileName(fileName).totalSize(totalSize));
    }
    public String complete() throws ApiException {
        return fileApi.completeUpload(md5);
    }
    public void cancel() {
    }
}
